package io.github.source.media.bean;

import android.net.Uri;

import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.orhanobut.logger.Logger;

import java.io.IOException;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.collection.ArrayMap;
import io.github.source.Sniffer;
import io.github.source.Source;
import io.github.source.bean.Site;
import io.github.source.bean.Url;
import io.github.source.config.VodConfig;
import io.github.source.parse.ParseJob;
import okhttp3.Call;
import okhttp3.Response;


/**
 * @ClassName: MediaPlayProviderImpl
 * @Description: (获取播放信息)
 * @author: huangrongcai
 * @date: 2024/6/21
 * @Copyright: 黄嵘才（HuangRc)
 */
class MediaPlayProviderImpl implements MediaPlayProvider {
    private static final String TAG = "Source.Media.Play.Provider.default";
    private final AMedia aMedia;
    final MediaQuery originalQuery;

    public static MediaPlayProvider newCall(AMedia aMedia, MediaQuery originalQuery) {
        MediaPlayProviderImpl call = new MediaPlayProviderImpl(aMedia, originalQuery);
        return call;
    }

    MediaPlayProviderImpl(AMedia aMedia, MediaQuery query) {
        this.aMedia = aMedia;
        this.originalQuery = query;
    }

    MediaPlayProviderImpl() {
        this(null, null);

    }

    @NonNull
    @Override
    public MediaResult<MediaPlay> getMediaPlayback(MediaQuery query, MediaBean video) {
        MediaResult<MediaPlay> result = null;
        try {
            // 获取播放信息
            MediaPlay play = fetchMediaPlay(query);

            // 解析（处理）播放信息
            result = parseMediaPlay(query, play);

            return result;
        } catch (Exception e) {
            Logger.t(TAG).e(e, "获取媒体播放数据异常");
            return MediaResult.error(500).message("获取媒体播放数据异常:" + e);
        } finally {
            loggerMediaPlay("返回", result);
        }

    }

    //记录日志
    private void loggerOnQuery(Site site, MediaQuery query) {
        Logger.t(TAG).d("请求播放信息---> "
                + "site=" + site + "\n"
                + "query=" + query);
    }

    private void loggerOnQueryReturn(MediaPlay play) {
        //日志
        Logger.t(TAG).d("请求播放信息<--- play=" + play);
    }

    /**
     * 输出播放信息的日志数据
     *
     * @param playResult 播放信息
     */
    private void loggerMediaPlay(String msg, MediaResult<MediaPlay> playResult) {
        if (playResult != null) {
            MediaPlay play = playResult.getData();
            StringBuilder sb = new StringBuilder();
            sb.append("播放 <--- ");
            sb.append(msg);
            if (play != null) {
                sb.append("url=").append(play.getPlayUrl()).append("\n");
                sb.append("header=" + play.getHeader());
            }
            Logger.t(TAG).d(sb);
        } else {
            Logger.t(TAG).d("播放 play=" + null);
        }
    }

    private MediaPlay getMediaPlay(MediaPlay play, MediaQuery query) {
        //从playUrl中获取解析出可播放的
        String url = query.getPlayUrl();
        if (Sniffer.isVideoFormat(url)) {
            String playUrl = "";
            playUrl = Sniffer.getVideoUrl(url);
            String siteKey = query.getSiteKey();
            Site site = VodConfig.get().getSite(siteKey);
            if (play == null) {
                play = MediaPlay.empty();
            }
            play.setPlayUrl(playUrl);
            play.setHeaders(play, site.getHeader());
            return play;
        }

        return play;

    }


    private MediaPlay fetchMediaPlay(MediaQuery query) throws Exception {
        /*query 里的地址是可能是播放的地址？1，优先检查query.playUrl是不是可以直接播放*/
        Source.get().stop();

        String siteKey = query.getSiteKey();
        Site site = VodConfig.get().getSite(siteKey);

        loggerOnQuery(site, query);
        MediaPlay play = null;

        if (site.getType() == 3) {
            play = getPlayContentBySpider(site, query);
        } else if (site.getType() == 4) {
            play = getPlayContentByHttp(site, query);
        } else if (site.isEmpty() && "push_agent".equals(siteKey)) {/*推送的播放源*/
            play = getPlayContentByPush(site, query);
        } else {
            play = getPlayContentByDefault(site, query);
        }
        /*几种常见playUrl(要转义http)
         * 1.NBY-2210c8758b4a0c805bea6818e421fa5b|http://121.62.61.51:6888/api/?key=BxzJDoznSIoiPuDrRm&url=
         * https://v.cdnlz3.com/20240718/24900_41aca672/index.m3u8|http://43.248.186.15:8082/jx/?url=
         * https://c1.rrcdnbf3.com/video/tangchaoguishiluzhixixing/第01集/index.m3u8|http://43.248.186.15:8082/jx/?url=
         * http://www.iqiyi.com/v_186njga2r64.html|https://cdn.suxun.site/api/?key=vV2dLM1za9kCV2LHTr&url=
         *Feiyun-oSoVRf|2FVPhr7aQjWE4uW0|2Fwr5ai9DeU7o2mlwFQumWE2gL20zEGYck|2BZOsM|2FFzsw5LdqKwwV|2BSXns|2FC0n5EpDg|3D|3D-FYNB1
         * https://www.tpvod.com/player.html?uri=https%3A%2F%2Fsd8.taopianplay1.com%3A43333%2Fc56b1bc09da3%2FHD%2F2024-07-09%2F15%2F9428ee0cd07c%2Ff7e0dae453eb%2Fplaylist.m3u8
         https://www.brovod.com/play/188267-6-1/
         * data:application/vn....这类好像EXO播放器可以解析，IJK不行。可以通过site 里的playerType = 2
         * 有需要通过WebView解析
         * */

        /*如果Play的播放地址不合规，则从查询里重新获取*/
        if (!Sniffer.isVideoFormat(play.getPlayUrl())) {
            play = getMediaPlay(play, query);
        }

        loggerOnQueryReturn(play);
        return play;
    }

    private String call(Site site, ArrayMap<String, String> params, boolean limit) throws IOException {
        Call call = fetchExt(site, params, limit).length() <= 1000 ? OkHttp.newCall(site.getApi(), site.getHeaders(), params) : OkHttp.newCall(site.getApi(), site.getHeaders(), OkHttp.toBody(params));
        return call.execute().body().string();
    }

    private String fetchExt(Site site, ArrayMap<String, String> params, boolean limit) throws IOException {
        String extend = site.getExt();
        if (extend.startsWith("http")) extend = fetchExt(site);
        if (limit && extend.length() > 1000) extend = extend.substring(0, 1000);
        if (!extend.isEmpty()) params.put("extend", extend);
        return extend;
    }

    private String fetchExt(Site site) throws IOException {
        Response res = OkHttp.newCall(site.getExt(), site.getHeaders()).execute();
        if (res.code() != 200) return "";
        site.setExt(res.body().string());
        return site.getExt();
    }

    //尝试解析(如有必要)
    private MediaResult<MediaPlay> parseMediaPlay(MediaQuery query, MediaPlay play) {
        Logger.t(TAG).d("解析播放信息---> "
                + "play=" + play + "\n"
                + "query=" + query
        );
        if (play == null) {
            return MediaResult.empty().message("播放信息 play=" + null);
        }
        //还需要再析析一下
        if (ParseJob.needParseMediaPlay(play)) {
            play = ParseJob.create(play).execute();
        }
        //2再检查播放地址
        Logger.t(TAG).d("解析播放信息<--- play=" + play);
        if (play != null) {
            return MediaResult.success(play);
        } else {
            return MediaResult.empty().message("播放信息 play=" + null);
        }

    }

    /**
     * 从爬虫获取播放信息
     *
     * @param site  Site
     * @param query MediaQuery 参数
     * @return MediaPlay
     * @throws Exception 异常
     */
    private MediaPlay getPlayContentBySpider(Site site, MediaQuery query) throws Exception {
        Spider spider = VodConfig.get().getSpider(site);
        String flag = query.getPlayFlag();
        String id = query.getPlayUrl();
        List<String> vipFlag = VodConfig.get().getFlags();
        Logger.t(TAG).d("spider Player request:" + " ,spider=" + spider + " ,flag=" + flag + " ,id=" + id + " ,vipFlag=" + vipFlag);
        String playerContent = spider.playerContent(flag, id, vipFlag);/*异常时*/

        Logger.t(TAG).d("spider Player Content:" + playerContent);
        VodConfig.get().setRecent(site);
        //封装播放地址
        MediaPlay play = MediaPlay.objectFrom(playerContent);
        play.setFlag(flag);
        play.setPlayUrl(Source.get().fetch(play));
        play.setHeaders(play, site.getHeader());
        play.setKey(site.getKey());

        return play;
    }

    /**
     * 从网络获取播放信息
     *
     * @param site  Site
     * @param query MediaQuery
     * @return MediaPlay
     * @throws Exception 异常
     */
    private MediaPlay getPlayContentByHttp(Site site, MediaQuery query) throws Exception {
        String id = query.getPlayUrl();
        String flag = query.getPlayFlag();
        ArrayMap<String, String> params = new ArrayMap<>();
        params.put("play", id);
        params.put("flag", flag);
        String playerContent = call(site, params, true);/*网络请求*/
        Logger.t(TAG).d("http playerContent:" + playerContent);

        MediaPlay play = MediaPlay.objectFrom(playerContent);
        play.setFlag(flag);
        play.setPlayUrl(Source.get().fetch(play));
        play.setHeaders(play, site.getHeader());

        return play;
    }

    /**
     * 从推送获取
     *
     * @param site  源站
     * @param query 参数
     * @return MediaPlay
     * @throws Exception
     */
    private MediaPlay getPlayContentByPush(Site site, MediaQuery query) throws Exception {
        String id = query.getPlayUrl();
        String flag = query.getPlayFlag();

        MediaPlay play = MediaPlay.objectFrom("");

        play.setParse(0);
        play.setFlag(flag);
        play.setUrl(Url.create().add(id));
        play.setPlayUrl(Source.get().fetch(play));
        play.setHeaders(play, site.getHeader());

        return play;
    }

    /**
     * 从默认获取
     *
     * @param site  Site
     * @param query MediaQuery
     * @return MediaPlay
     * @throws Exception
     */
    private MediaPlay getPlayContentByDefault(Site site, MediaQuery query) throws Exception {
        String id = query.getPlayUrl();
        String flag = query.getPlayFlag();
        Url url = Url.create().add(id);
        String type = Uri.parse(id).getQueryParameter("type");
        if ("json".equals(type)) {
            String rep = OkHttp.newCall(id, site.getHeaders()).execute().body().string();
            url = MediaPlay.objectFrom(rep).getUrl();/*取得播放地址*/
        }

        MediaPlay play = MediaPlay.objectFrom("{}");//直接封装返回
        play.setUrl(url);
        play.setFlag(flag);
        play.setPlayUrl(Source.get().fetch(play));
        play.setHeaders(play, site.getHeader());
        play.setParse(Sniffer.isVideoFormat(url.v()) && play.getPlayUrl().isEmpty() ? 0 : 1);

        return play;
    }

}
